#nullable enable
using System;
using System.Globalization;
using System.Text.Json;
using System.Text.Json.Serialization;

namespace ERP.Api.Infrastructure.Json
{
    public abstract class NullableConverterBase<T> : JsonConverter<T?> where T : struct
    {
        protected abstract bool TryParse(string s, out T value);
        protected virtual T ParseWithCulture(string s, CultureInfo culture)
        {
            if (typeof(T) == typeof(DateTime))
            {
                if (DateTime.TryParse(s, culture, DateTimeStyles.AssumeLocal, out var dt))
                    return (T)(object)dt;
            }
            throw new NotSupportedException();
        }

        public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            if (reader.TokenType == JsonTokenType.Null)
                return null;

            if (reader.TokenType == JsonTokenType.String)
            {
                var raw = reader.GetString();
                if (string.IsNullOrWhiteSpace(raw))
                    return null;

                if (TryParse(raw!, out var v))
                    return v;

                // 尝试按当前文化解析（日期场景等）
                try
                {
                    var v2 = ParseWithCulture(raw!, CultureInfo.CurrentCulture);
                    return v2;
                }
                catch { }

                throw new JsonException($"值 '{raw}' 无法转换为 {typeof(T).Name}?");
            }

            // 直接是数值/布尔类型
            try
            {
                if (typeof(T) == typeof(decimal))
                    return (T?)(object)reader.GetDecimal();
                if (typeof(T) == typeof(int))
                    return (T?)(object)reader.GetInt32();
                if (typeof(T) == typeof(long))
                    return (T?)(object)reader.GetInt64();
                if (typeof(T) == typeof(bool))
                    return (T?)(object)reader.GetBoolean();
                if (typeof(T) == typeof(DateTime))
                    return (T?)(object)reader.GetDateTime();
            }
            catch (Exception ex)
            {
                throw new JsonException(ex.Message, ex);
            }

            throw new JsonException($"不支持的 JSON Token: {reader.TokenType}");
        }

        public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options)
        {
            if (value == null)
            {
                writer.WriteNullValue();
                return;
            }
            if (typeof(T) == typeof(DateTime))
            {
                var dt = (DateTime)(object)value.Value;
                writer.WriteStringValue(dt);
                return;
            }
            writer.WriteStringValue(value.Value.ToString());
        }
    }

    public sealed class NullableDecimalConverter : NullableConverterBase<decimal>
    {
        protected override bool TryParse(string s, out decimal value) => decimal.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out value);
    }
    public sealed class NullableIntConverter : NullableConverterBase<int>
    {
        protected override bool TryParse(string s, out int value) => int.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out value);
    }
    public sealed class NullableLongConverter : NullableConverterBase<long>
    {
        protected override bool TryParse(string s, out long value) => long.TryParse(s, NumberStyles.Any, CultureInfo.CurrentCulture, out value);
    }
    public sealed class NullableBoolConverter : NullableConverterBase<bool>
    {
        protected override bool TryParse(string s, out bool value) => bool.TryParse(s, out value);
    }
    public sealed class NullableDateTimeConverter : NullableConverterBase<DateTime>
    {
        protected override bool TryParse(string s, out DateTime value)
        {
            if (DateTime.TryParse(s, CultureInfo.CurrentCulture, DateTimeStyles.AssumeLocal, out value)) return true;
            return DateTime.TryParse(s, CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal, out value);
        }

        protected override DateTime ParseWithCulture(string s, CultureInfo culture)
        {
            if (DateTime.TryParse(s, culture, DateTimeStyles.AssumeLocal, out var dt)) return dt;
            throw new FormatException($"值 '{s}' 不是有效的日期时间格式");
        }
    }
}
